/**
 * @(#)CodeEntityReadRelation.java, 2008-4-30.
 * Copyright 2008  Program Analysis Research Group(PARG),Institute of Software, Peking University.
 * All rights reserved.
 */
package edu.pku.sei.pgie.analyzer.internal.relation;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.FieldAccess;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.QualifiedName;
import org.eclipse.jdt.core.dom.ThisExpression;
import org.eclipse.jdt.core.dom.TypeDeclaration;

import edu.pku.sei.pgie.analyzer.internal.CodeEntitySymbolTable;
import edu.pku.sei.pgie.analyzer.util.ASTUtil;

/**
 * @author HeLi
 */
public class CodeEntityReadRelation extends AbstractCodeEntityRelation{

    class ReadVisitor extends ASTVisitor {
        List<String[]> container;

        Stack<String> typeDeclarationStack;

        public ReadVisitor() {
            this.container = new ArrayList<String[]>();
            typeDeclarationStack = new Stack<String>();
        }

        public List<String[]> getResult() {
            return container;
        }

        public boolean visit(FieldAccess node) {
            Expression expr = node.getExpression();
            if (expr instanceof ThisExpression)
                return true;
            String typeName = (String) typeDeclarationStack.peek();
            ITypeBinding typeBinding = expr.resolveTypeBinding();
            if (typeBinding == null)
                return true;
            String fqn = typeBinding.getQualifiedName();
            container.add(new String[] {
                typeName, fqn
            });
            return true;
        }

        public boolean visit(QualifiedName node) {
            if (typeDeclarationStack.isEmpty())
                return false;
            String fqn = ASTUtil.getRefrenceSiteBinding(node);
            if (fqn == null)
                return false;
            String typeName = (String) typeDeclarationStack.peek();
            container.add(new String[] {
                typeName, fqn
            });
            return false;
        }

        public boolean visit(TypeDeclaration node) {
            ITypeBinding typeBinding = node.resolveBinding();
            if (typeBinding == null)
                return true;
            String fqn = typeBinding.getQualifiedName();
            typeDeclarationStack.push(fqn);
            return true;
        }

        public void endVisit(TypeDeclaration node) {
            if (!typeDeclarationStack.isEmpty()) {
                typeDeclarationStack.pop();
            }
        }
    }

    public String[][] collectCallBack(CompilationUnit root,
            CodeEntitySymbolTable symbolTable) throws Exception {
        ReadVisitor visitor = new ReadVisitor();
        root.accept(visitor);
        List<String[]> result = visitor.getResult();
        return result.toArray(new String[result.size()][]);
    }

}
